package com.gitee.neuray.security.admin.role.biz;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gitee.neuray.security.admin.authority.*;
import com.gitee.neuray.security.admin.constant.AdminCommonConstant;
import com.gitee.neuray.security.admin.element.biz.AdminElementBiz;
import com.gitee.neuray.security.admin.element.entity.AdminElementEntity;
import com.gitee.neuray.security.admin.menu.biz.AdminMenuBiz;
import com.gitee.neuray.security.admin.menu.entity.AdminMenuEntity;
import com.gitee.neuray.security.admin.menu.mapper.AdminMenuMapper;
import com.gitee.neuray.security.admin.roleresource.biz.AdminResourcerolemapBiz;
import com.gitee.neuray.security.admin.roleresource.entity.AdminResourcerolemapEntity;
import com.gitee.neuray.security.admin.roleresource.mapper.AdminResourcerolemapMapper;
import com.gitee.neuray.security.admin.userrole.biz.AdminRoleusermapBiz;
import com.gitee.neuray.security.admin.userrole.entity.AdminRoleusermapEntity;
import com.gitee.neuray.security.auth.client.config.SysAuthConfig;
import com.gitee.neuray.security.common.exception.BaseException;
import com.gitee.neuray.security.common.util.EntityUtils;
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import org.springframework.transaction.annotation.Transactional;
import com.gitee.neuray.security.common.biz.BaseBiz;
import com.gitee.neuray.security.admin.role.mapper.AdminRoleMapper;
import com.gitee.neuray.security.admin.role.entity.AdminRoleEntity;
import tk.mybatis.mapper.entity.Example;


@Service
@Transactional(rollbackFor = Exception.class)
public class AdminRoleBiz extends BaseBiz<AdminRoleMapper, AdminRoleEntity> {
    @Override
    protected String getPageName() {
        return "AdminRole" + "Biz";
    }

    @Autowired
    private AdminMenuMapper menuMapper;
    @Autowired
    private AdminElementBiz elementBiz;
    @Autowired
    private AdminResourcerolemapMapper resourceRoleMapMapper;
    @Autowired
    private AdminRoleusermapBiz roleusermapBiz;
    @Autowired
    private SysAuthConfig sysAuthConfig;
    @Autowired
    private AdminResourcerolemapBiz adminResourcerolemapBiz;
    @Autowired
    private AdminMenuBiz menuBiz;

    /**
     * 通过角色id获取角色数和角色树下的elements
     *
     * @param roleId
     */
    public List<AdminMenuDto> selectAuthorityMenuTree(String roleId) {
        List<String> roleIds = new ArrayList<>();
        roleIds.add(roleId);
        List<AdminMenuDto> roleMenus = bulid(menuMapper.selectAll(), "root", roleIds);
        return roleMenus;
    }

    public void modifyAuthorityMenus(String roleId, List<AdminMenuDto> permissionList) {
        if (StringUtils.isEmpty(roleId) || permissionList.isEmpty()) {
            throw new BaseException("args is null...");
        }
        //用roleId删除所有与角色相关的资源
        Example resourceRoleExample = new Example(AdminResourcerolemapEntity.class);
        resourceRoleExample.createCriteria().andEqualTo("roleId", roleId);
        int deleteCount = resourceRoleMapMapper.deleteByExample(resourceRoleExample);
        if (deleteCount < 0) {
            throw new BaseException("系统异常错误...");
        }
        //删除完成后，重新插入menu到资源表中,批量插入数据
        List<AdminResourcerolemapEntity> roleMenus = Lists.newArrayList();
        setRoleResource(roleMenus, permissionList, roleId);
        resourceRoleMapMapper.batchInsert(roleMenus);
    }

    /**
     * 递归设置字段
     *
     * @param roleMenus
     * @param permissionList
     * @param roleId
     */
    private void setRoleResource(List<AdminResourcerolemapEntity> roleMenus, List<AdminMenuDto> permissionList, String roleId) {
        permissionList.forEach(adminMenu -> {
            if (adminMenu.isCheckout()) {
                roleMenus.add(setRoleResource(roleId, adminMenu.getId(), AdminCommonConstant.RESOURCE_TYPE_MENU));
            }
            if (adminMenu.getElements() != null && adminMenu.getElements().size() > 0) {
                adminMenu.getElements().forEach(elementDto -> {
                    if (elementDto.getDefaultCheck()) {
                        roleMenus.add(setRoleResource(roleId, elementDto.getId(), AdminCommonConstant.RESOURCE_TYPE_BTN));
                    }
                });
            }
            if (adminMenu.getChildren() != null && adminMenu.getChildren().size() > 0) {
                setRoleResource(roleMenus, adminMenu.getChildren(), roleId);
            }
        });
    }

    private AdminResourcerolemapEntity setRoleResource(String roleId, String resourceId, String type) {
        AdminResourcerolemapEntity resourceEntity = new AdminResourcerolemapEntity();
        resourceEntity.setRoleId(roleId);
        resourceEntity.setResourceType(type);
        resourceEntity.setResourceId(resourceId);
        EntityUtils.setCreatAndUpdatInfo(resourceEntity);
        return resourceEntity;
    }

    /**
     * 通过用户id查询用户角色
     *
     * @param userId 用户id
     * @return 角色实体类
     */
    public List<AdminRoleEntity> getRoleByUserId(String userId) {
        AdminRoleusermapEntity roleUserParams = new AdminRoleusermapEntity();
        roleUserParams.setUserId(userId);
        List<AdminRoleusermapEntity> roleList = roleusermapBiz.selectList(roleUserParams);
        List<AdminRoleEntity> allRole = mapper.selectAll();
        List<AdminRoleEntity> resultRole = new ArrayList<>();
        for (AdminRoleusermapEntity roleUserMap :
                roleList) {
            resultRole.addAll(allRole.stream().filter((AdminRoleEntity role) -> roleUserMap.getRoleId().equals(role.getId())).collect(Collectors.toList()));
        }
        return resultRole;
    }

    public List<PermissionElementDto> checkAuthorityElements(List<String> roleId) throws Exception {
        List<AdminResourcerolemapEntity> roleElements;
        //获取roleid下的所有的接口
        /*AdminResourcerolemapEntity temp = new AdminResourcerolemapEntity();
        temp.setRoleId(roleId);*/
        Example example = new Example(AdminResourcerolemapEntity.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("roleId",roleId);
        roleElements = resourceRoleMapMapper.selectByExample(example);
        //roleElements = resourceRoleMapMapper.select(temp);
        List<AdminResourcerolemapEntity> elements = roleElements.parallelStream().filter(element -> Objects.equals(element.getResourceType(), AdminCommonConstant.RESOURCE_TYPE_BTN)).collect(Collectors.toList());
        List<AdminResourcerolemapEntity> menus = roleElements.parallelStream().filter(element -> Objects.equals(element.getResourceType(), AdminCommonConstant.RESOURCE_TYPE_MENU)).collect(Collectors.toList());
        //遍历所有的按钮权限，获取按钮对应的菜单的短地址，用作按钮的短地址
        List<PermissionElementDto> permissionElementDtos = Lists.newArrayList();
        //遍历按钮的资源，反找按钮对应的菜单的短地址和菜单的名称
        elements.forEach(entity -> {
            AdminElementEntity adminElementEntity = elementBiz.selectById(entity.getResourceId());
            if (adminElementEntity != null) {
                PermissionElementDto elementDto = new PermissionElementDto();
                AdminMenuEntity adminMenuEntity = menuBiz.selectById(adminElementEntity.getMenuId());
                //脏数据判断,没有这个有element没有菜单，不可能的
                if (adminMenuEntity != null) {
                    BeanUtils.copyProperties(adminMenuEntity, elementDto);
                    elementDto.setMethod(adminElementEntity.getMethod());
                    permissionElementDtos.add(elementDto);
                }
            }
        });
        //遍历菜单，也放在角色资源下，方便网关权限校验的方式为菜单和按钮鉴权的两种
        menus.forEach(menu -> {
            AdminMenuEntity adminMenuEntity = menuBiz.selectById(menu.getResourceId());
            if (adminMenuEntity != null) {
                PermissionElementDto elementDto = new PermissionElementDto();
                BeanUtils.copyProperties(adminMenuEntity, elementDto);
                permissionElementDtos.add(elementDto);
            }
        });
        return permissionElementDtos;
    }
    //public List<AdminMenuDto> authorityMenus(String roleId) {
    public List<AdminMenuDto> authorityMenus(List<String> roleId,boolean isSys) {
        //定义固定返回参数
        List<AdminMenuDto> resultPermission = new ArrayList<>();
        //获取权限下的menu
        List<AdminMenuEntity> menus = null;
        //判断是否是系统的超级管理员
        if (isSys) {
            menus = menuMapper.selectAll();
        }else {
            menus = menuMapper.selectMenuByRoleId(roleId);
        }
        //渲染树形结构，如果为null，证明没有菜单
        if (menus != null) {
            resultPermission = this.bulid(menus, "root", roleId);
        }
        resultPermission = resultPermission.stream().sorted(Comparator.comparing(AdminMenuDto::getOrderNum)).collect(Collectors.toList());
        return resultPermission;

    }
    //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>私有化方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    /**
     * 带父级节点的建树
     *
     * @param menus
     * @param root
     * @return
     */
    public List<AdminMenuDto> bulid(List<AdminMenuEntity> menus, Object root, List<String> roleId) {
        List<AdminMenuDto> trees = new ArrayList<AdminMenuDto>();
        for (AdminMenuEntity treeNode : menus) {
            if (Objects.equals(AdminCommonConstant.BASE_MENU_TYPE, treeNode.getType())) {
                continue;
            }
            AdminMenuDto menuDto = transferMenuDto(treeNode, roleId);
            if (root.equals(treeNode.getParentId())) {
                trees.add(menuDto);
            }
            setChildren(menuDto, menus, roleId);
        }
        return trees;
    }

    private void setChildren(AdminMenuDto treeNode, List<AdminMenuEntity> menus, List<String> roleId) {
        for (AdminMenuEntity it : menus) {
            if (Objects.equals(AdminCommonConstant.BASE_MENU_TYPE, it.getType())) {
                continue;
            }
            if (it.getParentId().equals(treeNode.getId())) {
                AdminMenuDto menuDto = transferMenuDto(it, roleId);
                if (treeNode.getChildren() == null) {
                    treeNode.setChildren(new ArrayList<>());
                }
                treeNode.add(menuDto);
            }
        }
    }

    private AdminMenuDto transferMenuDto(AdminMenuEntity adminMenuEntity, List<String> roleId) {
        AdminMenuDto menuDto = new AdminMenuDto();
        menuDto.setParentId(adminMenuEntity.getParentId());
        menuDto.setId(adminMenuEntity.getId());
        menuDto.setName(adminMenuEntity.getCode());
        menuDto.setOrderNum(adminMenuEntity.getOrderNum());
        AdminMetaDto metaDto = JSONObject.parseObject(JSONObject.toJSONString(adminMenuEntity), AdminMetaDto.class);
        menuDto.setMeta(metaDto);
        //按角色渲染菜单和按钮
        if (roleId != null && roleId.size() != 0) {
            menuDto.setCheckout(getCheckout(roleId, adminMenuEntity.getId(), AdminCommonConstant.RESOURCE_TYPE_MENU));
            //设置menu下的被选中的权限按钮
            menuDto.setElements(getRoleMenuElements(roleId, adminMenuEntity.getId()));
        }
        return menuDto;
    }

    private boolean getCheckout(List<String> roleId, String resourceId, String type) {
        //如果是超级管理员直接返回true
        boolean bool = roleId.stream().filter(item -> Objects.equals(item, sysAuthConfig.getSysUsername())).findAny().isPresent();
        if (Objects.equals(roleId, sysAuthConfig.getSysUsername())) {
            return true;
        }
        List<AdminResourcerolemapEntity> roleMenus = getResourceRole(roleId, resourceId, type);
        return roleMenus.size() > 0 ? true : false;
    }

    /**
     * 获取角色资源表中的菜单和按钮信息
     *
     * @param roleIds
     * @param mapId
     * @param type
     * @return
     */
    private List<AdminResourcerolemapEntity> getResourceRole(List<String> roleIds, String mapId, String type) {
        List<AdminResourcerolemapEntity> ret = new ArrayList<>();
        for(String roleId : roleIds){
            AdminResourcerolemapEntity temp = new AdminResourcerolemapEntity();
            temp.setRoleId(roleId);
            temp.setResourceId(mapId);
            temp.setResourceType(type);
            ret.addAll(adminResourcerolemapBiz.selectList(temp));
        }
        //按照id查重
        List<AdminResourcerolemapEntity> unique = ret.stream().collect(
                Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(AdminResourcerolemapEntity :: getId))), ArrayList::new)
        );
        return unique;
    }

    private List<AdminElementsDto> getRoleMenuElements(List<String> roleId, String menuId) {
        if (roleId == null || StringUtils.isEmpty(menuId)) {
            return null;
        }
        AdminElementEntity elementTemp = new AdminElementEntity();
        elementTemp.setMenuId(menuId);
        List<AdminElementEntity> adminElementEntities = elementBiz.selectList(elementTemp);
        List<AdminElementsDto> adminElementsDtos = JSONArray.parseArray(JSONObject.toJSONString(adminElementEntities), AdminElementsDto.class);
        adminElementsDtos.forEach(element -> {
            element.setDefaultCheck(getCheckout(roleId,element.getId(),AdminCommonConstant.RESOURCE_TYPE_BTN));
        });
        return adminElementsDtos;
    }
}
